﻿namespace Patterns4Net.Core
{
    using System.Collections.Generic;
    using System.Diagnostics.Contracts;
    using System.Linq;

    public static class ArgumentsParser
    {
        public static T Parse<T>(string[] args, IList<string> arguments, IList<string> errors) where T : new()
        {
            Contract.Requires(args != null);
            Contract.Requires(arguments != null);
            Contract.Requires(errors != null);
            Contract.Ensures(Contract.Result<T>() != null);

            var result = new T();
            var emptyArray = new object[0];
            var properties = typeof(T).GetProperties()
                .Where(p => p.CanWrite)
                .Where(p => p.PropertyType == typeof(string) || p.PropertyType == typeof(bool));

            for (int i = 0; i < args.Length; i++)
            {
                if (args[i].StartsWith("-") == false)
                {
                    // just ordinary argument - no option
                    arguments.Add(args[i]);
                    continue;
                }

                var optionName = args[i].Substring(1).Replace("-", string.Empty).ToUpperInvariant();
                var property = properties.Where(p => p.Name.ToUpperInvariant() == optionName).FirstOrDefault();
                if (property == null)
                {
                    errors.Add(string.Format("Option {0} is not supported.", args[i]));
                }
                else
                {
                    if (property.PropertyType == typeof(bool))
                    {
                        property.SetValue(result, true, emptyArray);
                    }
                    else
                    {
                        i++;
                        if (i >= args.Length)
                        {
                            errors.Add(string.Format("Option -{0} is not fallowed by it's value.", optionName));
                        }
                        else
                        {
                            property.SetValue(result, args[i], emptyArray);
                        }
                    }
                }
            }

            return result;
        }
    }
}
